<?php
/**
 * 安全增强服务
 * 提供全面的安全检查和防护机制
 */

declare(strict_types=1);

namespace app\service;

use think\facade\Db;
use think\facade\Log;
use think\facade\Cache;
use think\facade\Request;

class SecurityEnhancementService
{
    /**
     * 安全配置
     */
    private const SECURITY_CONFIG = [
        'max_login_attempts' => 5,          // 最大登录尝试次数
        'lockout_duration' => 1800,        // 锁定时长（秒）
        'password_min_length' => 8,        // 密码最小长度
        'password_complexity' => true,      // 密码复杂度要求
        'session_timeout' => 7200,         // 会话超时时间
        'ip_whitelist_enabled' => false,   // IP白名单启用
        'api_rate_limit' => 1000,          // API请求频率限制（每小时）
        'sql_injection_protection' => true, // SQL注入防护
        'xss_protection' => true,          // XSS防护
        'csrf_protection' => true,         // CSRF防护
    ];

    /**
     * 安全威胁等级
     */
    private const THREAT_LEVELS = [
        'LOW' => 1,
        'MEDIUM' => 2,
        'HIGH' => 3,
        'CRITICAL' => 4
    ];

    /**
     * 安全事件类型
     */
    private const EVENT_TYPES = [
        'LOGIN_FAILURE' => '登录失败',
        'BRUTE_FORCE' => '暴力破解',
        'UNAUTHORIZED_ACCESS' => '未授权访问',
        'PRIVILEGE_ESCALATION' => '权限提升',
        'DATA_BREACH_ATTEMPT' => '数据泄露尝试',
        'SQL_INJECTION' => 'SQL注入攻击',
        'XSS_ATTACK' => 'XSS攻击',
        'CSRF_ATTACK' => 'CSRF攻击',
        'SUSPICIOUS_ACTIVITY' => '可疑活动'
    ];

    /**
     * 验证用户登录安全
     */
    public function validateLoginSecurity(string $username, string $password, string $ip): array
    {
        $result = [
            'allowed' => false,
            'reason' => '',
            'threat_level' => self::THREAT_LEVELS['LOW'],
            'security_measures' => []
        ];

        try {
            // 1. 检查IP黑名单
            if ($this->isIpBlacklisted($ip)) {
                $result['reason'] = 'IP地址已被禁止访问';
                $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
                $this->logSecurityEvent('UNAUTHORIZED_ACCESS', $username, $ip, '黑名单IP访问');
                return $result;
            }

            // 2. 检查登录尝试次数
            $attempts = $this->getLoginAttempts($username, $ip);
            if ($attempts >= self::SECURITY_CONFIG['max_login_attempts']) {
                $result['reason'] = '登录尝试次数过多，账户已锁定';
                $result['threat_level'] = self::THREAT_LEVELS['MEDIUM'];
                $this->logSecurityEvent('BRUTE_FORCE', $username, $ip, "登录尝试{$attempts}次");
                return $result;
            }

            // 3. 验证密码强度
            if (!$this->validatePasswordSecurity($password)) {
                $result['reason'] = '密码不符合安全要求';
                $result['threat_level'] = self::THREAT_LEVELS['LOW'];
                return $result;
            }

            // 4. 检查用户状态
            $userSecurity = $this->getUserSecurityStatus($username);
            if (!$userSecurity['active']) {
                $result['reason'] = $userSecurity['reason'];
                $result['threat_level'] = self::THREAT_LEVELS['MEDIUM'];
                return $result;
            }

            // 5. 检查异常登录模式
            $anomaly = $this->detectLoginAnomaly($username, $ip);
            if ($anomaly['detected']) {
                $result['security_measures'][] = 'require_additional_verification';
                $result['threat_level'] = self::THREAT_LEVELS['MEDIUM'];
                $this->logSecurityEvent('SUSPICIOUS_ACTIVITY', $username, $ip, $anomaly['reason']);
            }

            $result['allowed'] = true;
            return $result;

        } catch (\Exception $e) {
            Log::error('登录安全验证失败: ' . $e->getMessage());
            $result['reason'] = '安全验证异常';
            $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
            return $result;
        }
    }

    /**
     * 验证数据访问权限安全
     */
    public function validateDataAccessSecurity(int $userId, string $module, int $dataId, array $context = []): array
    {
        $result = [
            'allowed' => false,
            'reason' => '',
            'threat_level' => self::THREAT_LEVELS['LOW'],
            'audit_log' => true
        ];

        try {
            // 1. 基础权限检查
            $hasBasicPermission = $this->checkBasicDataPermission($userId, $module, $dataId);
            if (!$hasBasicPermission) {
                $result['reason'] = '无基础数据访问权限';
                $result['threat_level'] = self::THREAT_LEVELS['MEDIUM'];
                $this->logSecurityEvent('UNAUTHORIZED_ACCESS', "user_$userId", $this->getClientIp(), 
                    "尝试访问无权限数据: {$module}#{$dataId}");
                return $result;
            }

            // 2. 时间窗口检查
            if (!$this->checkTimeBasedAccess($userId, $module)) {
                $result['reason'] = '当前时间不允许访问该数据';
                $result['threat_level'] = self::THREAT_LEVELS['LOW'];
                return $result;
            }

            // 3. 行为模式检查
            $behaviorCheck = $this->analyzeBehaviorPattern($userId, $module, $context);
            if (!$behaviorCheck['normal']) {
                $result['reason'] = $behaviorCheck['reason'];
                $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
                $this->logSecurityEvent('SUSPICIOUS_ACTIVITY', "user_$userId", $this->getClientIp(), 
                    $behaviorCheck['reason']);
                return $result;
            }

            // 4. 敏感数据额外检查
            if ($this->isSensitiveData($module, $dataId)) {
                $sensitiveCheck = $this->validateSensitiveDataAccess($userId, $module, $dataId);
                if (!$sensitiveCheck['allowed']) {
                    $result['reason'] = $sensitiveCheck['reason'];
                    $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
                    return $result;
                }
            }

            $result['allowed'] = true;
            return $result;

        } catch (\Exception $e) {
            Log::error('数据访问安全验证失败: ' . $e->getMessage());
            $result['reason'] = '安全验证异常';
            $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
            return $result;
        }
    }

    /**
     * 验证API请求安全
     */
    public function validateApiSecurity(string $endpoint, array $params = []): array
    {
        $result = [
            'allowed' => false,
            'reason' => '',
            'threat_level' => self::THREAT_LEVELS['LOW']
        ];

        try {
            $ip = $this->getClientIp();

            // 1. 频率限制检查
            if (!$this->checkRateLimit($ip, $endpoint)) {
                $result['reason'] = 'API请求频率超限';
                $result['threat_level'] = self::THREAT_LEVELS['MEDIUM'];
                return $result;
            }

            // 2. SQL注入检测
            if (self::SECURITY_CONFIG['sql_injection_protection'] && $this->detectSqlInjection($params)) {
                $result['reason'] = '检测到SQL注入尝试';
                $result['threat_level'] = self::THREAT_LEVELS['CRITICAL'];
                $this->logSecurityEvent('SQL_INJECTION', 'unknown', $ip, "端点: $endpoint");
                return $result;
            }

            // 3. XSS攻击检测
            if (self::SECURITY_CONFIG['xss_protection'] && $this->detectXssAttack($params)) {
                $result['reason'] = '检测到XSS攻击尝试';
                $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
                $this->logSecurityEvent('XSS_ATTACK', 'unknown', $ip, "端点: $endpoint");
                return $result;
            }

            // 4. CSRF检测
            if (self::SECURITY_CONFIG['csrf_protection'] && $this->detectCsrfAttack()) {
                $result['reason'] = '检测到CSRF攻击尝试';
                $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
                $this->logSecurityEvent('CSRF_ATTACK', 'unknown', $ip, "端点: $endpoint");
                return $result;
            }

            // 5. 参数安全检查
            $paramCheck = $this->validateParameterSecurity($params);
            if (!$paramCheck['valid']) {
                $result['reason'] = $paramCheck['reason'];
                $result['threat_level'] = self::THREAT_LEVELS['MEDIUM'];
                return $result;
            }

            $result['allowed'] = true;
            return $result;

        } catch (\Exception $e) {
            Log::error('API安全验证失败: ' . $e->getMessage());
            $result['reason'] = '安全验证异常';
            $result['threat_level'] = self::THREAT_LEVELS['HIGH'];
            return $result;
        }
    }

    /**
     * 检查IP是否在黑名单中
     */
    private function isIpBlacklisted(string $ip): bool
    {
        $cacheKey = "security:ip_blacklist:$ip";
        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        // 检查数据库中的IP黑名单
        $blacklisted = Db::name('security_ip_blacklist')
            ->where('ip', $ip)
            ->where('expire_time', '>', time())
            ->count() > 0;

        Cache::set($cacheKey, $blacklisted, 300); // 缓存5分钟
        return $blacklisted;
    }

    /**
     * 获取登录尝试次数
     */
    private function getLoginAttempts(string $username, string $ip): int
    {
        $cacheKey = "security:login_attempts:{$username}:{$ip}";
        return (int)Cache::get($cacheKey, 0);
    }

    /**
     * 增加登录尝试次数
     */
    public function incrementLoginAttempts(string $username, string $ip): void
    {
        $cacheKey = "security:login_attempts:{$username}:{$ip}";
        $attempts = $this->getLoginAttempts($username, $ip) + 1;
        Cache::set($cacheKey, $attempts, self::SECURITY_CONFIG['lockout_duration']);

        // 记录登录失败
        $this->logSecurityEvent('LOGIN_FAILURE', $username, $ip, "第{$attempts}次登录失败");
    }

    /**
     * 清除登录尝试计数
     */
    public function clearLoginAttempts(string $username, string $ip): void
    {
        $cacheKey = "security:login_attempts:{$username}:{$ip}";
        Cache::delete($cacheKey);
    }

    /**
     * 验证密码安全性
     */
    private function validatePasswordSecurity(string $password): bool
    {
        if (strlen($password) < self::SECURITY_CONFIG['password_min_length']) {
            return false;
        }

        if (self::SECURITY_CONFIG['password_complexity']) {
            // 检查密码复杂度：至少包含大小写字母、数字和特殊字符
            $hasLower = preg_match('/[a-z]/', $password);
            $hasUpper = preg_match('/[A-Z]/', $password);
            $hasNumber = preg_match('/\d/', $password);
            $hasSpecial = preg_match('/[^a-zA-Z\d]/', $password);

            return $hasLower && $hasUpper && $hasNumber && $hasSpecial;
        }

        return true;
    }

    /**
     * 获取用户安全状态
     */
    private function getUserSecurityStatus(string $username): array
    {
        $user = Db::name('admin')->where('username', $username)->find();
        
        if (!$user) {
            return ['active' => false, 'reason' => '用户不存在'];
        }

        if ($user['status'] < 0) {
            return ['active' => false, 'reason' => '用户账户已禁用'];
        }

        // 检查是否需要强制修改密码
        if (isset($user['password_updated']) && 
            time() - $user['password_updated'] > 90 * 24 * 3600) {
            return ['active' => false, 'reason' => '密码已过期，需要更新'];
        }

        return ['active' => true, 'reason' => ''];
    }

    /**
     * 检测登录异常模式
     */
    private function detectLoginAnomaly(string $username, string $ip): array
    {
        // 检查异常时间登录
        $hour = (int)date('H');
        if ($hour < 6 || $hour > 22) {
            return [
                'detected' => true,
                'reason' => '非正常时间登录'
            ];
        }

        // 检查异常IP地理位置（简化版本）
        if ($this->isUnusualLocation($username, $ip)) {
            return [
                'detected' => true,
                'reason' => '异常地理位置登录'
            ];
        }

        return ['detected' => false, 'reason' => ''];
    }

    /**
     * 记录安全事件
     */
    private function logSecurityEvent(string $eventType, string $username, string $ip, string $details): void
    {
        try {
            Db::name('security_events')->insert([
                'event_type' => $eventType,
                'username' => $username,
                'ip_address' => $ip,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'details' => $details,
                'threat_level' => self::THREAT_LEVELS[array_search($eventType, array_keys(self::EVENT_TYPES)) !== false ? 'MEDIUM' : 'LOW'],
                'create_time' => time()
            ]);

            // 高威胁事件立即通知管理员
            if (in_array($eventType, ['SQL_INJECTION', 'XSS_ATTACK', 'BRUTE_FORCE'])) {
                $this->notifyAdministrator($eventType, $username, $ip, $details);
            }
        } catch (\Exception $e) {
            Log::error('安全事件记录失败: ' . $e->getMessage());
        }
    }

    /**
     * 获取客户端IP
     */
    private function getClientIp($request = null): string
    {
        if ($request && method_exists($request, 'ip')) {
            return $request->ip();
        }
        return Request::ip();
    }

    /**
     * 检查基础数据权限
     */
    private function checkBasicDataPermission(int $userId, string $module, int $dataId): bool
    {
        // 调用数据权限服务进行检查
        $permissionService = new DataPermissionService();
        return $permissionService->checkDataAccess($userId, $module, $dataId);
    }

    /**
     * 检查时间基础访问权限
     */
    private function checkTimeBasedAccess(int $userId, string $module): bool
    {
        // 简化版本：检查工作时间
        $hour = (int)date('H');
        return $hour >= 8 && $hour <= 18;
    }

    /**
     * 分析行为模式
     */
    private function analyzeBehaviorPattern(int $userId, string $module, array $context): array
    {
        // 简化版本：检查访问频率
        $cacheKey = "security:access_pattern:{$userId}:{$module}";
        $accessCount = (int)Cache::get($cacheKey, 0);
        
        if ($accessCount > 100) { // 每小时超过100次访问
            return [
                'normal' => false,
                'reason' => '访问频率异常'
            ];
        }

        Cache::set($cacheKey, $accessCount + 1, 3600);
        return ['normal' => true, 'reason' => ''];
    }

    /**
     * 检查是否为敏感数据
     */
    private function isSensitiveData(string $module, int $dataId): bool
    {
        $sensitiveModules = ['admin', 'financial', 'salary'];
        return in_array($module, $sensitiveModules);
    }

    /**
     * 验证敏感数据访问
     */
    private function validateSensitiveDataAccess(int $userId, string $module, int $dataId): array
    {
        // 敏感数据需要额外验证
        return [
            'allowed' => true, // 简化版本
            'reason' => ''
        ];
    }

    /**
     * 检查API频率限制
     */
    private function checkRateLimit(string $ip, string $endpoint): bool
    {
        $cacheKey = "security:rate_limit:{$ip}:{$endpoint}";
        $requests = (int)Cache::get($cacheKey, 0);
        
        if ($requests >= self::SECURITY_CONFIG['api_rate_limit']) {
            return false;
        }

        Cache::set($cacheKey, $requests + 1, 3600); // 1小时窗口
        return true;
    }

    /**
     * 检测SQL注入
     */
    private function detectSqlInjection(array $params): bool
    {
        $sqlPatterns = [
            '/(\bUNION\b.*\bSELECT\b)/i',
            '/(\bSELECT\b.*\bFROM\b)/i',
            '/(\bINSERT\b.*\bINTO\b)/i',
            '/(\bDELETE\b.*\bFROM\b)/i',
            '/(\bUPDATE\b.*\bSET\b)/i',
            '/(\bDROP\b.*\bTABLE\b)/i',
            '/(\bEXEC\b|\bEXECUTE\b)/i',
            '/(\'|\").*(\bOR\b|\bAND\b).*(\=|\>|\<)/i'
        ];

        foreach ($params as $value) {
            if (is_string($value)) {
                foreach ($sqlPatterns as $pattern) {
                    if (preg_match($pattern, $value)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检测XSS攻击
     */
    private function detectXssAttack(array $params): bool
    {
        $xssPatterns = [
            '/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/i',
            '/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/i',
            '/on\w+\s*=\s*["\'].*["\']/i',
            '/javascript\s*:/i',
            '/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/i',
            '/<embed\b[^<]*(?:(?!<\/embed>)<[^<]*)*<\/embed>/i'
        ];

        foreach ($params as $value) {
            if (is_string($value)) {
                foreach ($xssPatterns as $pattern) {
                    if (preg_match($pattern, $value)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检测CSRF攻击
     */
    private function detectCsrfAttack(): bool
    {
        // 简化版本：检查Referer
        $referer = $_SERVER['HTTP_REFERER'] ?? '';
        $host = $_SERVER['HTTP_HOST'] ?? '';
        
        if (empty($referer)) {
            return false; // 可能的CSRF，但在此简化处理
        }

        return !str_contains($referer, $host);
    }

    /**
     * 验证参数安全性
     */
    private function validateParameterSecurity(array $params): array
    {
        foreach ($params as $key => $value) {
            if (is_string($value)) {
                // 检查参数长度
                if (strlen($value) > 10000) {
                    return [
                        'valid' => false,
                        'reason' => '参数长度超限'
                    ];
                }

                // 检查特殊字符
                if (preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', $value)) {
                    return [
                        'valid' => false,
                        'reason' => '包含非法字符'
                    ];
                }
            }
        }

        return ['valid' => true, 'reason' => ''];
    }

    /**
     * 检查是否异常位置
     */
    private function isUnusualLocation(string $username, string $ip): bool
    {
        // 简化版本：检查用户历史登录IP
        $recentIps = Cache::get("security:user_ips:$username", []);
        return !in_array($ip, $recentIps);
    }

    /**
     * 通知管理员
     */
    private function notifyAdministrator(string $eventType, string $username, string $ip, string $details): void
    {
        // TODO: 实现管理员通知功能（邮件、短信等）
        Log::critical("安全警报: {$eventType} - 用户: {$username}, IP: {$ip}, 详情: {$details}");
    }
}